/*我的工具库
-------------------------------------------------------------------------------*/

/* 1.cookie 的设置&获取&删除方法
-------------------------------------------------------------------------------*/
/* 设置cookie
 * 参数 name: 设置这条 cookie 的名字
 * 参数 value: 设置这条 cookie 的值
 * 参数 iDay: 这是这条 cookie 的过期时间
 * 参数 path: 设置 cookie 保存路径
 * 参数 domain: 设置 cookie 所在域名
 * 格式 setCookie("userName","梅宪淋",7,"/","localhost");
 **************************************/
function setCookie(name, value, iDay, path, domain) {

    //1.处理 cookie 默认保存路径
    //1.1 获取当前路径中"/"最后一次出现的下标位置
    //例如：https://www.w3cschool.cn/pegosu/ikndjozt.html
    var index = window.location.pathname.lastIndexOf("/");
    //window.location.pathname 用于获取当前网页对应的路径

    //1.2 截取从0到index之间的字符串，作为当前路径
    var currentPath = window.location.pathname.slice(0, index);

    //1.3 如果传入了 path 则使用传入的 path,没传入，则使用 currentPath
    path = path || currentPath;

    //2.处理 cookie 的所在域名
    //如果传入了 domain,则等于传入的 domain;没传入则等于默认的 domain
    //document.domain 用于获取当前网页对应的域名 
    domain = domain || document.domain;

    var oDate = new Date();

    oDate.setDate(oDate.getDate() + iDay);

    document.cookie = name + "=" + value + ";expires=" + oDate + ";path=" + path + ";domain=" + domain;
}

/* 获取cookie
 * 参数 name: 要获取的 cookie 的名字
 **************************************/
function getCookie(name) {
    //将cookie中的数据分割成数组
    var arr = document.cookie.split('; ');

    for (var i = 0; i < arr.length; i ++) {
        var arr2 = arr[i].split('=');

        if (arr2[0] == name) {
            return arr2[1];
        }
    }

    return '';
}

/* 删除 cookie
 * 参数 name: 这条 cookie 的名字
 * 参数 path: 这条 cookie 保存的路径
 * 格式: removeCookie("userName", "/")
 ****************************************/
function removeCookie(name, path) {
    //调用 setCookie 函数，并设置过期时间为 -1，即昨天，就 OK了
    setCookie(name, 1, -1, path);
    //如果设置 cookie 时没有修改 path 的话,就不用管它
    //如果设置 cookie 时修改了 path,那么就必须在删除时传入这个路径,否则删不掉
}



/*2.拖拽元素方法:普通拖拽(可拖拽出可视区)&限制范围拖拽(仅限可视区内)
------------------------------------------------------------------------------*/
/*(1)普通拖拽用法: new Drag("id");
 *参数: id => 元素的id,不加井号,例如 new Drag("box");
---------------------------------------------------
 *(2)限制范围拖拽用法: new LimitDrag("id");
 *参数: id => 元素的id,不加井号,例如 new LimitDrag("box");
---------------------------------------------------------*/

/*普通拖拽方法
------------------------------------*/
function Drag(id) {
    var _this = this;

    this.disX = 0;
    this.disY = 0;

    this.oDiv = document.getElementById(id);

    if (this.oDiv.setCapture) {
        this.oDiv.onmousedown = function (e) {
            _this.fnDown(e);
            
            _this.oDiv.setCapture();
            return false
        };
    } else {
        this.oDiv.onmousedown = function (e) {
            _this.fnDown(e);
    
            return false
        };
    }

}

//鼠标移动
Drag.prototype.fnMove = function (e) {
    var oEvent = e || event;

    this.oDiv.style.left = oEvent.clientX - this.disX + 'px';
    this.oDiv.style.top = oEvent.clientY - this.disY + 'px';
}

//鼠标抬起
Drag.prototype.fnUp = function () {
    document.onmousemove = null;
    document.onmouseup = null;
}

//兼容IE
Drag.prototype.fnUpForIE = function () {
    document.onmousemove = null;
    document.onmouseup = null;
    this.oDiv.releaseCapture();
}

//鼠标按下
Drag.prototype.fnDown = function (e) {
    var _this = this;
    var oEvent = e || event;

    this.oDiv.style.position = 'absolute';  //绝对定位
    this.disX = oEvent.clientX - this.oDiv.offsetLeft;
    this.disY = oEvent.clientY - this.oDiv.offsetTop;

    document.onmousemove = function (e) {
        _this.fnMove(e);
    }

    if (this.oDiv.setCapture) {
        document.onmouseup = function () {
            _this.fnUpForIE();
        }
    } else {
        document.onmouseup = function () {
            _this.fnUp();
        }
    }
}


/*限制范围拖拽
-----------------------------------*/
//从Drag中继承属性和方法
function LimitDrag(id) {
    Drag.call(this, id)  //继承属性
}

//LimitDrag.prototype = Object.create(Drag.prototype);  //继承方法
//LimitDrag.prototype.constructor = LimitDrag;  //改变引用
//更好的兼容性
for (var i in Drag.prototype) {
    LimitDrag.prototype[i] = Drag.prototype[i];
}

//改变(重写)方法
LimitDrag.prototype.fnMove = function (e) {
    var oEvent = e || event;

    var l = oEvent.clientX - this.disX;
    var t = oEvent.clientY -this.disY;

    if (l < 0) {
        l = 0;
    } else if (l > document.documentElement.clientWidth - this.oDiv.offsetWidth) {
        l = document.documentElement.clientWidth - this.oDiv.offsetWidth
    }

    if (t < 0) {
        t = 0;
    } else if (t > document.documentElement.clientHeight - this.oDiv.offsetHeight) {
        t = document.documentElement.clientHeight - this.oDiv.offsetHeight
    }

    this.oDiv.style.left = l + 'px';
    this.oDiv.style.top = t + 'px';
}



/*3.获取非行内样式方法
-------------------------------------------------------------------------------*/
//用法：getStyle(oDiv, "width")
function getStyle(obj, name) {

    //判断 obj.currentStyle 的值，
    //IE下会返回 true，Chrome等其它浏览器下会返回 false
    if (obj.currentStyle) {
        //IE
        return obj.currentStyle[name]
    } else {
        //Chrome等其它浏览器
        return getComputedStyle(obj)[name]
    }
}



/*4.完美运动框架
-------------------------------------------------------------------------------*/
//完美运动框架
/* obj: 要设置的元素,  
 * json: 属性&值,例如: {width: 300, height: 300} 
 * fnEnd: 回调函数*/
function startMove(obj, json, fnEnd) {
    //先清空定时器一次
    clearInterval(obj.timer);

    //设置定时器
    obj.timer = setInterval(function () {

        var bStop = true;   //假设所有的值都已经到了

        for (var attr in json) {
            var cur = 0;

            //针对透明度属性单独设置(因为透明度有小数，而且单位不是px)
            if (attr == 'opacity') {
                //Math.round方法用于四舍五入(用于消除有时会出现的一大串小数)
                cur = Math.round(parseFloat(getStyle(obj, attr)) * 100) //这里乘100是为了方便
            } else {
                cur = parseInt(getStyle(obj, attr))
            }
            //设置速度(减速运动)
            var speed = (json[attr] - cur) / 6;
            //减速运动必须进行取整运算
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

            if (cur != json[attr]) {
                bStop = false;
            }
            
            if (attr == 'opacity') {
                //对透明度进行单独处理
                obj.style.filter = 'alpha(opacity:' + (cur + speed) + ')';
                obj.style[attr] = (cur + speed) / 100; //除IE外其他浏览器
            } else {
                obj.style[attr] = cur + speed + "px";
            }
        }
        
        if (bStop) {
            clearInterval(obj.timer);
            if (fnEnd) {
                fnEnd()
            }
        }
        
    }, 30);
}



/*5.Ajax方法
--------------------------------------------------------------------------------*/
//将对象转换成字符串方法
function obj2str(data) {
    /*1.传进来的obj是下面的格式
    {
        "userName": "mxl",
        "passWord": "123456"
    }
    */
    data.t = new Date().getTime();
    //new Date().getTime() 的作用是让GET请求每次都不同,
    //防止浏览器(特别是IE)使用缓存的数据,导致页面数据无法更新
    /*2.此时传进来的data是下面的格式(添加了 t 属性并赋值为当前时间)
    {
        "userName": "mxl",
        "passWord": "123456",
        "t": "461894654916"
    }
    */
    var res = [];
    for (var key in data) {
        //在 URL 中是不可以出现中文的,如果出现了中文则需要转码
        //可以通过encodeURIComponent()进行转码
        res.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); 
        //[userName=mxl,passWord=123456,t=461864]
    }
    return res.join("&");   //userName=mxl&passWord=123456&t=461864
    
}

//通过Ajax获取数据
/*调用格式:
{
    type: "GET",
    url: "test.php",
    data: {
        "userName": "mxl",
        "passWord": "123456"
    },
    timeout: 3000,
    success: function (str) {
        alert(str.responseText/str.responseXML);
    },
    failed: function (str) {
        alert(str);
    }
}
----------------------------------------------------------------*/
/*参数说明:
 *参数 type: 使用 GET/POST 类型
 *参数 url: 要请求的数据文件名(请求地址),例如 'test.php'
 *参数 data: 要获取的具体属性名和值,例如 {"userName":"mxl","passWord":"123456"}
 *参数 timeout: 设置超时时间,如果超出该时间还没获取到数据,则终止请求,例如 3000
 *参数 success: 成功时执行的函数,例如 function(str){alert(str.responseText/responseXML)}
 *参数 failed：失败时执行的函数,例如 function(str){alert(str)}
 ----------------------------------------------------------------*/
function ajax(option) {
    //0.调用上面定义的方法,将传递进来的对象(参数obj)转换为字符串
    if (option.data) {
        var str = obj2str(option.data); //key=value&key=value;
    }
    //1.创建 Ajax 对象(XMLHttpRequest对象)
    var oAjax;
    if (window.XMLHttpRequest)
    {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        oAjax = new XMLHttpRequest();
    }
    else
    {
        // code for IE6, IE5
        oAjax = new ActiveXObject("Microsoft.XMLHTTP");
    }  
    console.log(oAjax); 

    //2.设置向服务器发送的请求内容(方法, 文件名, 是否异步)
    //判断类型为 GET/POST,分别执行不同的方法
    if (option.type.toLowerCase() === "get") {
        oAjax.open(option.type, option.url + '?' + str, true);
        //3.发送请求
        oAjax.send(); 
    } else {
        oAjax.open(option.type, option.url, true);
        //POST关键代码
        oAjax.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        //3.发送请求
        oAjax.send(str);
    }


    //4.接收返回的数据
    oAjax.onreadystatechange = function name(params) {
        //判断是否读取完成
        if (oAjax.readyState == 4) {
            clearInterval(timer);
            if (oAjax.status == 200) {
                //成功
                //调用函数 success,并且将 oAjax 的值作为参数传给它
                option.success(oAjax);
            } else {
                //失败
                //如果传进来了这个失败时执行的函数,那么我们就去调用它
                //因为并不是所有时候都需要对获取失败进行处理的
                if (option.failed) {
                    option.failed(oAjax.status);
                }
            }
        }     
    }

    //5. 判断是否传入超时时间
    var timer;
    if (option.timeout) {
        timer = setInterval(function () {
            console.log("请求超时");
            oAjax.abort(); //终止请求
            clearInterval(timer);
        }, option.timeout);
    }
}



/*6.兼容addEventListener方法
-------------------------------------------------------------------------------*/
//将兼容 addEventListener 和 attachEvent 的代码封装函数
//obj: 元素，ev: 事件名，fn: 事件处理函数
function myAddEvent(obj, ev, fn) {
    // if (obj.attachEvent) {
    //     //IE7、IE8
    //     obj.attachEvent('on' + ev, fn);
    // } else {
    //     //Chrome等主流浏览器
    //     obj.addEventListener(ev, fn, false);
    // }
    if (obj.addEventListener) {
        //Chrome等主流浏览器
        obj.addEventListener(ev, fn, false);
    } else if (obj.attachEvent) {
        //IE7、IE8
        obj.attachEvent('on' + ev, function () {
            fn.call(obj);
        })
    } else {
        obj['on' + type] = fn;
    }
}

//使用方法如下:
// window.onload = function name(params) {
//     var oBtn = document.getElementById('btn');

//     myAddEvent(oBtn, 'click', function () {
//         alert('a');
//     });
//     myAddEvent(oBtn, 'click', function () {
//         alert('b');
//     });
// }



/*7.对象继承 => 圣杯模式
----------------------------------------------------------------------------*/
//圣杯模式继承
//Target:  要继承别人的构造函数
//Origin: 要被继承的构造函数
//用法如下: inherit(Son, Father);
var inherit = (function () {
    var F = function () {}
    return function (Target, Origin) {
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        //重新定义构造器指向
        Target.prototype.constructor = Target;
        //获取继承来源
        Target.prototype.uber = Origin.prototype; 
    }
}());



/*8.对象克隆方法
--------------------------------------------------------------------------*/
//用法: deepClone(obj, obj1)
function deepClone(origin, target) {
            
    var target = target || {},  //判断是否传入target,传入了则使用传入的,没传入则使用{}
        toStr = Object.prototype.toString,  //区分数组与对象时会用到,为了方便保存出来
        arrStr = "[object Array]";   //如果是数组,则会返回"[object Array]"

    //循环要克隆的对象
    for (var prop in origin) {

        //过滤掉该对象原型上的属性
        if (origin.hasOwnProperty(prop)) {
            //判断原始值
            if (origin[prop] !== 'null' && typeof(origin[prop]) == 'object') {
                //引用值(数组和对象会返回 'object')
                if (toStr.call(origin[prop]) == arrStr) {
                    //数组
                    target[prop] = []
                } else {
                    //对象
                    target[prop] = {}
                }

                //递归(如果是引用值,则继续执行上面的步骤,直到是原始值才退出)
                deepClone(origin[prop], target[prop]);
            } else {
                //原始值
                target[prop] = origin[prop];
            }
        }
    }
    return target;
}



/*9.数据类型判断方法
-------------------------------------------------------------------------*/
//用法：type(要判断数据类型的数据)
function type(target) {
    var ret = typeof(target);
    var template = {
        "[object Array]": "array",
        "[object Object]": "object",
        "[object Number]": "number-object",
        "[object Boolean]": "boolean-object",
        "[object String]": "string-object"
    }
    if (target === null) {
        return "null";
    } else if (ret == "object") {
        var str = Object.prototype.toString.call(target);
        return template[str];
    } else {
        return ret;
    }
}



/*10.获取滚动条滚动距离方法(兼容所有浏览器)
------------------------------------------------------------------------*/
//用法 1：getScrollOffset() 返回对象
//用法 2：getScrollOffset().x 返回横(X轴)方向滚动条滚动距离
//用法 3：getScrollOffset().y 返回纵(Y轴)方向滚动条滚动距离
function getScrollOffset() {
    
    if (window.pageXOffset) {
        return {
            x: window.pageXOffset,
            y: window.pageYOffset
        }
    } else {
        return {
            x: document.body.scrollLeft + document.documentElement.scrollLeft,
            y: document.body.scrollTop + document.documentElement.scrollTop
        }
    }
}



/*11.获取当前可视区尺寸方法
-------------------------------------------------------------------------------*/
//用法 1：getViewportOffset() 返回对象
//用法 2：getViewportOffset().w 返回当前可视区域宽度
//用法 3：getViewportOffset().h 返回当前可视区域高度
function getViewportOffset() {
    if (window.innerWidth) {
        return {
            w: window.innerWidth,
            h: window.innerHeight
        }
    } else {
        //诡异模式下document.compatMode会返回"BackCompat"
        if (document.compatMode === "BackCompat") {
            return {
                w: document.body.clientWidth,
                h: document.body.clientHeight
            }
        } else {
            return {
                w: document.documentElement.clientWidth,
                h: document.documentElement.clientHeight
            }
        }
    }
} 


/*12.阻止事件冒泡
------------------------------------------------------------------------------*/
//用法：stopBubble(e)
function stopBubble(event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }
}


/*13.阻止默认行为
------------------------------------------------------------------------------*/
//用法：stopDefault(e)
function stopDefault(event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false;
    }
}


/*14.通过class类名获取动态创建的元素
------------------------------------------------------------------------------*/
//1. 用法：getEleByClass(oWrapper, "box")
//2. 参数 oWrapper 指的是通过获取 DOM 元素的方法获取到的 DOM 元素
//3. 参数 "box" 指的是要获取哪个类名的元素,需要加引号,不需要加点
//4. 返回值是一个"数组"
function getEleByClass(parent, clsName) {

    //创建一个数组,用来存储获取到的所有符合条件的元素
    var getEleByClassArr = [];  

    //获取外层父元素内的所有子元素
    var aElements = parent.getElementsByTagName("*");

    //循环遍历 parent 内所有子元素
    for (var i = 0;i < aElements.length;i ++) {
        if (aElements[i].className == clsName) {
            getEleByClassArr.push(aElements[i]);
        }
    }

    return getEleByClassArr;
}